#ifndef SIMPLE_IO_PERMISSIONS_H
#define SIMPLE_IO_PERMISSIONS_H

#include <string>

namespace simple::io
{
	enum class permission_flags : unsigned {};

	template <bool set_subject, unsigned subject, unsigned flags>
	class permission_chain
	{
		public:

		[[nodiscard]] constexpr auto owner() noexcept
		{ return permission_chain<true, (subject * set_subject) | 0b001'000'000u, flags>(); }
		[[nodiscard]] constexpr auto group() noexcept
		{ return permission_chain<true, (subject * set_subject) | 0b000'001'000u, flags>(); }
		[[nodiscard]] constexpr auto others() noexcept
		{ return permission_chain<true, (subject * set_subject) | 0b000'000'001u, flags>(); }
		[[nodiscard]] constexpr auto everyone() noexcept
		{ return owner().group().others(); }

		[[nodiscard]] constexpr auto execute() noexcept
		{ static_assert(subject != 0); return permission_chain<false, subject, flags | subject>(); }
		[[nodiscard]] constexpr auto write() noexcept
		{ static_assert(subject != 0); return permission_chain<false, subject, flags | subject << 1>(); }
		[[nodiscard]] constexpr auto read() noexcept
		{ static_assert(subject != 0); return permission_chain<false, subject, flags | subject << 2>(); }
		[[nodiscard]] constexpr auto everything() noexcept
		{ return read().write().execute(); }
		[[nodiscard]] constexpr auto nothing() noexcept
		{ static_assert(subject == 0); return static_cast<permission_flags>(*this); }

		[[nodiscard]] constexpr operator permission_flags() noexcept
		{ return static_cast<permission_flags>(flags); }

		private:
		constexpr permission_chain() noexcept {}
		// [[nodiscard]] // cause std is dumb, what can I say
		// https://stackoverflow.com/questions/52332203/friend-member-functions-and-attributes-gcc-vs-clang
		friend constexpr auto allow() noexcept;
		template<bool, unsigned, unsigned>
		friend class permission_chain;
	};

	[[nodiscard]] constexpr auto allow() noexcept { return permission_chain<true,0,0>(); };

	permission_flags swap_process_permission_mask(permission_flags) noexcept;

	[[nodiscard]] std::string get_message(permission_flags);

} // namespace simple::io

#endif /* end of include guard */
